package com.zlx.mall.basic.web.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zlx.mall.basic.trace.MDCUtil;
import com.zlx.mall.basic.web.constant.TraceConstants;
import com.zlx.mall.basic.web.holder.IdContextHolder;
import com.zlx.mall.basic.web.holder.RequestContextHolder;
import com.zlx.mall.basic.web.model.RequestWrapper;
import com.zlx.mall.basic.web.model.ResponseWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

/**
 * @author qingke
 * @see org.springframework.web.filter.CommonsRequestLoggingFilter
 **/
public class RequestFilter extends AbstractRequestFilter {

    private final Logger log;

    public RequestFilter(ObjectMapper objectMapper, Logger log) {
        super(objectMapper);
        this.log = log;
    }

    public RequestFilter(ObjectMapper objectMapper) {
        super(objectMapper);
        this.log = LoggerFactory.getLogger(RequestFilter.class);
    }

    @Override
    protected void beforeRequest(RequestWrapper requestWrapper) {

        requestWrapper.startStopWatch();

        RequestContextHolder.setHeaders(requestWrapper.getHeaders());
        RequestContextHolder.setUri(requestWrapper.getUri());
        RequestContextHolder.setUriVars(requestWrapper.getUriVars());
        RequestContextHolder.setRemoteAddress(requestWrapper.getRemoteAddress());
        RequestContextHolder.setCookies(requestWrapper.getCookies());
        RequestContextHolder.setContent(requestWrapper.getContentAsString());

        String traceId = requestWrapper.getHeaders().getFirst(TraceConstants.HTTP_HEADER_TRACE_ID);
        if (StringUtils.hasText(traceId)) {
            MDCUtil.setTraceId(traceId);
        } else {
            MDCUtil.getOrCreateTraceId();
        }
    }

    @Override
    protected void afterRequest(RequestWrapper requestWrapper,
                                ResponseWrapper responseWrapper) {

        log.info("> HTTP | ID:{} | IP:{} | Method:{} | Status:{} | URI:{} | URIVars:{} | RequestHeaders:{} | RequestBody:{} | ResponseHeaders:{} | ResponseBody:{} | Time:{}ms",
                ObjectUtils.getDisplayString(IdContextHolder.getId()),
                requestWrapper.getRemoteAddress(),
                requestWrapper.getMethod(),
                responseWrapper.getStatus(),
                requestWrapper.getRequestURI(),
                multiValueMapToPrettyString(requestWrapper.getUriVars()),
                multiValueMapToPrettyString(requestWrapper.getHeaders()),
                requestBodyToPrettyString(requestWrapper),
                multiValueMapToPrettyString(responseWrapper.getHeaders()),
                responseBodyToPrettyString(responseWrapper),
                requestWrapper.getStopWatchTime());

        // remove thread context
        ContextHolderListener.remove();
        MDCUtil.clear();
    }


}
